#include "Vector3.h"
#include <math.h>
#include <sstream>
#include <iomanip>

using namespace std;

Vector3::Vector3() {
	zero();
}

Vector3::Vector3(const Vector3 &v) {
	x = v.x;
	y = v.y;
	z = v.z;
}

std::string Vector3::toString() {
	stringstream stream;
	stream << "[" << fixed << setprecision(3) << setw(8) << x << ", "
			<< setprecision(3) << setw(8) << y << ", " << setprecision(3)
			<< setw(8) << z << "]";
	return stream.str();
}

Vector3::Vector3(float x, float y, float z) {
	this->x = x;
	this->y = y;
	this->z = z;
}

float Vector3::length() const {
	return sqrt(x * x + y * y + z * z);
}

Vector3 Vector3::cross(const Vector3 &v) {
	return Vector3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
}

Vector3 Vector3::normalize() {
	Vector3 v;
	float magSq = x * x + y * y + z * z;
	if (magSq > 0.0f) {
		float oneOverMag = 1.0f / sqrt(magSq);
		v.x = x * oneOverMag;
		v.y = y * oneOverMag;
		v.z = z * oneOverMag;
	}
	return v;
}

void Vector3::zero() {
	x = 0.0f;
	y = 0.0f;
	z = 0.0f;
}

Vector3& Vector3::operator =(const Vector3 &v) {
	x = v.x;
	y = v.y;
	z = v.z;
	return *this;
}

bool Vector3::operator ==(const Vector3 &v) const {
	return x == v.x && y == v.y && z == v.z;
}

bool Vector3::operator !=(const Vector3 &v) const {
	return x != v.x || y != v.y || z != v.z;
}

Vector3 Vector3::operator +(const Vector3 &v) const {
	return Vector3(x + v.x, y + v.y, z + v.z);
}

Vector3 Vector3::operator -(const Vector3 &v) const {
	return Vector3(x - v.x, y - v.y, z - v.z);
}

Vector3 Vector3::operator -() const {
	return Vector3(-x, -y, -z);
}

Vector3 Vector3::operator *(float n) const {
	return Vector3(x * n, y * n, z * n);
}

/**
 * Standard multiplication overrident to behave as
 * dot product.
 */
float Vector3::operator *(const Vector3 &v) const {
	return x * v.x + y * v.y + z * v.z;
}

Vector3 Vector3::operator /(float n) const {
	float oneOverN = 1.0f / n;
	return Vector3(x * oneOverN, y * oneOverN, z * oneOverN);
}

Vector3& Vector3::operator +=(const Vector3 &v) {
	x += v.x;
	y += v.y;
	z += v.z;
	return *this;
}

Vector3& Vector3::operator -=(const Vector3 &v) {
	x -= v.x;
	y -= v.y;
	z -= v.z;
	return *this;
}

Vector3& Vector3::operator *=(float n) {
	x *= n;
	y *= n;
	z *= z;
	return *this;
}

Vector3& Vector3::operator /=(float n) {
	float oneOverN = 1.0f / n;
	x *= oneOverN;
	y *= oneOverN;
	z *= oneOverN;
	return *this;
}
